package com.zlz.server.aspect;

import com.zlz.server.annotation.OperateLog;
import com.zlz.server.config.security.JwtTokenUtil;
import com.zlz.server.pojo.Oplog;
import com.zlz.server.pojo.RespBean;
import com.zlz.server.service.IOplogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author: zlz
 * @date: 2021/3/19 21:42
 * @description:
 * @since: JDK1.8
 */
@Aspect
@Component
@Slf4j
public class OperateLogAspect {
    public static final String FAILED = "failed";
    public static final String SUCCESS = "success";
    private static ThreadLocal<LogDetail> logDetails = new ThreadLocal<>();
    @Resource
    private HttpServletRequest httpServletRequest;

    @Value("${jwt.tokenHeader}")
    private String tokenHeader;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Resource
    private IOplogService iOplogService;

    @Pointcut("execution(public * com.zlz.server.controller.*Controller.*(..))")
    public void joinPointCut(){

    }

    @Around(value = "joinPointCut() && @annotation(operateLog)")
    public Object writeLog(ProceedingJoinPoint joinPoint, OperateLog operateLog) {
        Oplog oplog = new Oplog();
        oplog.setIp(getIpFromReq());
        oplog.setOperationTime(LocalDateTime.now());
        oplog.setModuleName(operateLog.moduleName());
        oplog.setOprLevel(operateLog.level().name());
        oplog.setOperationName(operateLog.operationName());
        oplog.setOperator(getUserNameFromReq());
        LogDetail logDetail = new LogDetail();
        logDetails.set(logDetail);
        Object object = null;
        try {
            object =  joinPoint.proceed();
            if (object instanceof RespBean) {
                RespBean respBean = (RespBean)object;
                if (respBean.getCode() != 200) {
                    oplog.setResult(FAILED);
                }
            }
            oplog.setResult(SUCCESS);
        } catch (Throwable throwable) {
            oplog.setResult(FAILED);
        } finally {
            oplog.setTarget(logDetails.get().target);
            oplog.setDetail(logDetails.get().detail == null ? args2Str(joinPoint.getArgs()) : logDetails.get().detail);
            logDetails.remove();
            iOplogService.save(oplog);
        }
        return  object;
    }

    private String args2Str(Object[] args) {
        if (Objects.isNull(args)) {
            return StringUtils.EMPTY;
        }
        List<Object> list = new ArrayList<>(Arrays.asList(args));
        return list.toString();
    }

    public static void setOperateTarget(String target) {
        logDetails.get().target = target;
    }

    public static void setOperateDetail(String detail) {
        logDetails.get().detail = detail;
    }

    private String getIpFromReq() {
        return httpServletRequest.getRemoteAddr();
    }

    private String getUserNameFromReq() {
        String authHeader = httpServletRequest.getHeader(tokenHeader);
        String authToken = authHeader.substring(tokenHead.length());
        return jwtTokenUtil.getUserNameFromToken(authToken);
    }
}
class LogDetail{
    String detail;
    String target;
}
